;   This program is free software: you can redistribute it and/or modify
;   it under the terms of the GNU General Public License as published by
;   the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.
;
;   This program is distributed in the hope that it will be useful,
;   but WITHOUT ANY WARRANTY; without even the implied warranty of
;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;   GNU General Public License for more details.
;
;   You should have received a copy of the GNU General Public License
;   along with this program.  If not, see <http://www.gnu.org/licenses/>.
;
;程序名称:clock.asm
;功能:常驻计时器/闹钟
;环境:16BIT DOS实模式
;编译器:MASM 5.1-6X
;用法:看说明
;返回值:没有
;破坏寄存器:不适用
;
;
;这是吧上某人的功课吧
;这题目有普遍性，涉及的问题较多，所以独立发一帖，希望多些人看到．
;
;参照 “定时响铃”的例子及其它MASM程序的例子,实现 INT 1C
;MYINT1C 实现的功能在屏幕的右上角显示秒表或时钟，按ESC，
;退出程序。
;说明：
;1.实现基本的秒表功能，即参照8.5范例给出的响铃程序改写，
;实现简单的计时和暂停、中止等功能；
;2.时钟复杂一些，按照书后BIOS/DOS中断附表实现从系
;统取时间，并能够对其进行设置和相应的计时功能。
;
;解题
;DOS的常驻，时钟比较简单，基本上拦截1CH，抓取系统时间，
;找个地方显示一下就完事了，至于计时，方法也有许多，1CH
;本身就是每1/18.2秒运行一次，所以同时也有计时功能．
;常驻的方法用DOS的21H,AH=31H或者INT27也可以．
;这个小小CLOCK程式的计时和读时间不用任何中断int21h,ah=2ch
;或int 1Ah,而是直接读取40:6C - 40:6D的系统累加时间，这相容度好像
;还大，测试在windows/dos 和dosbox都能正常运行
;编译：因为程式是com，masm 5.x 须要exe2bin  转成com>　exe2bin clock.exe clock.com
;masm 6.x的话加　ml /AT　的设定可直接转成com
;
;用法：
;clock   ;在右上角显示时间
;clock u  ; 移除常驻
;clock s mm:ss
;mm是分钟，ss是秒
;键入clock s 3:10  　
;右上角显示倒数计时3:10 ..3:09...3:08 直到00:00时显示3秒红色 -alarm-文字
;然后回到正常系统时间
;若键入　clock s 10，程式会视为倒数10分钟，若只要倒数秒
;可键入　clock s 0:10 ;则数10秒
;
;若clock已经常驻，也可以键入clock s mm:ss 去设定新的倒数
;代码有简单的英文注解（要交功课的同学请自行添加／翻译注解）
;
;
;
.286

remove_ax       equ     0AA01h
ask_ax          equ     0AA02h
alarm_set_ask   equ     0AA03h
exist_flag      equ     0AAFFh
time_att        equ     70h
alarm_att       equ     0cfh
alarm_time      equ     18*3    ; ?  alarm seconds

                cseg    segment
                assume  cs:cseg
                org     100h
begin:          jmp     init

;sign:           db      'WooWoo'
old_off         dw      0
old_seg         dw      0
delay_count     dw      0
time_up         db      0
work_flag       db      0
alarm_flag    db	0
alarm_count     dw      alarm_time

;------------- tsr start ------------------

int_start:      sti
                cmp     cs:work_flag,0  ;is it working ?
                jz      j10             ;yes, leave
                iret

j10:            mov     cs:work_flag,1  ;set working flag
                push    es
                push    si
                push    di
                push    bp
                pusha
                cmp     ax,remove_ax ; remove ?
                jnz     j20          ; no
                popa
                mov     ax,cs        ;restore old int 1ch
                mov     bx,exist_flag
                mov     cx,cs:old_off
                mov     dx,cs:old_seg
                jmp     j110
j20:
                cmp     ax,ask_ax    ;is it ask exist
                jnz     j50          ;no
                popa
                mov     bx,exist_flag
                jmp     j110
                ; do show time

j50:            cmp     ax,alarm_set_ask  ;is it timer setting ?
                jnz     j52               ;no
                mov     delay_count,cx    ;keep user timer
                dec     alarm_count       ;init alarm
                ;
j52:
                cmp     delay_count,0     ;is it end timer
                jnz     j53               ;no

                cmp     alarm_count,alarm_time ;is it alarm time ?
                jz      j60                    ; no
                jmp     short j55

.386

j53:            xor     eax,eax
                dec     delay_count
                mov     ax,delay_count
                jnz     j70

                ;       time_up
j55:
                dec     alarm_count     ;alarm end ?
                jz      j60             ;yes, back to current time

j59:            mov     bp,offset alarm_str ;print alarm string
				mov	bl,alarm_att
                mov     ax,cs
                mov     es,ax
                jmp     short j90


j60:            mov     ax,40h
				mov		es,ax
				mov		eax,dword ptr es:[006ch] ;get system time count

j70:            mov     ebx,10          ;change to hh:mm:ss format
				mul		ebx
				mov		ebx,182
				xor		edx,edx
				div		ebx   ;total seconds
				mov		ebx,60
				xor		edx,edx
				div		ebx   ;ax = min / edx = seconds
				mov		cl,dl ;second
				xor		edx,edx
				div		ebx   ;ax = hour / edx = min

.286
				mov		di,cs
				mov		es,di
				mov		di,offset time_str
				mov		bp,di
				add		al,0
                aam                ;BCD format
                or      ax,3030h   ;change to ASCII
				xchg	ah,al
                stosw
				inc		di
				mov		al,dl
				add		al,0
                aam
				or		ax,3030h
				xchg	ah,al
                stosw
				inc		di
				mov		al,cl
				add		al,0
                aam
				or		ax,3030h
				xchg	ah,al
                stosw
                mov     alarm_count,alarm_time  ;reset
                mov     bl,time_att

j90:            mov     dh,0       ;row
                mov     dl,80-8    ;column
				mov		cx,8
                mov     bh,0       ;page
                mov     ax,1300h   ;print timer
				int		10h

j100:
                popa

j110:			pop	 	bp
				pop	 	di
				pop	 	si
				pop	 	es
                mov     cs:work_flag,0 ;clear flag
                iret

;------------------------------------------------

time_str		db		'00:00:00',0
alarm_str		db		' -alarm-',0

tsr_end 		equ		$

not_exist       db      'clock not install!','$'
release_str     db      'clock removed!','$'
exist_str       db      'clock already installed!','$'
install_str     db      'clock installed',0dh,0ah
                db      'type clock s mm:ss to set timer.',0dh,0ah
                db      'type clock u to remove','$'
alarm_install   db      'alarm installed',0dh,0ah,'$'

over_limit      db      'over limit !!!',10,13,'$'
err_format      db      'times format error !!!',10,13,'$'

minute          dw      0
second          dw      0
min_limit       dw      60
sec_limit       dw      60
alarm_set       db      0

ratioa          dw      10
ratiob          dw      182
limit_time      equ     10

init:           mov     si,82h
                xor     cx,cx
                mov     cl,[si-2] ;get length
                jcxz    s70
                mov     al,[si]
                mov     bx,cx
                mov     byte ptr ds:[si+bx-1],0 ;clear 0dh
                and     al,11011111b ;upcase
                cmp     al,'U'       ;remove ?
                jz      s10
                cmp     al,'S'       ;timer ?
                jnz     s70
                call    read_time    ;change user input to hex number
                mov     alarm_set,0
                jc      short s70    ;input error
                mov     alarm_set,1
                jmp     short s70    ;input ok

s10:            mov     ax,remove_ax ;remove !
                int     1ch
                cmp     bx,exist_flag
                jz      s20          ;aleady exist
                mov     dx,offset not_exist

s15:            mov     ah,9
                int     21h
                mov     ah,4ch       ;quit
                int     21h

s20:            push    ax
                push    ax
                push    ds
                mov     ds,dx
                mov     dx,cx
                mov     ax,251ch     ;reset old int
                int     21h
                pop     ds
                pop     es  ; get tsr cs

                mov     ax,word ptr es:[002ch]
                mov     es,ax
                mov     ah,49h        ;release psp memory
                int     21h
                pop     es
                mov     ah,49h        ;release tsr memory
                int     21h
                mov     dx,offset release_str
                jmp     short s15


s70:            ; install, ask first
                ;

                mov     ax,remove_ax
                int     1ch
                cmp     bx,exist_flag
                jnz     s75
                cmp     alarm_set,1
                jz      s77
                mov     dx,offset exist_str
                jmp     s15
                ;       not install

s75:
                mov     al,1ch
                mov     ah,35h       ;read old 1ch
                int     21h
                mov     old_off,bx
                mov     old_seg,es
                mov     al,1ch
                mov     ah,25h       ;read our 1ch
                mov     dx,offset int_start
                int     21h

s77:            cmp     alarm_set,0
                jz      s80
                mov     ax,alarm_set_ask  ;set alarm, cx = user input
                mov     cx,delay_count
                int     1ch
                ;
                mov     dx,offset alarm_install
                jmp     short s90

s80:            mov     dx,offset install_str
s90:            mov     ah,9
                int     21h

                mov     dx,offset tsr_end
                int     27h                 ;stay my program and exit

;--------------------------------------------------------------
read_time:      ;read user input and change to hex

                add     si,2 ;point to time set
                mov     di,offset minute
                mov     bx,offset min_limit
                mov     cx,2
                push    cs
                pop     es

rt10:           xor     ax,ax
                lodsb
                cmp     byte ptr [si],':'
                jz      rt15
                cmp     byte ptr [si],0
                jz      rt15
                sub     al,'0'
                mov     ah,al
                lodsb
rt15:           sub     al,'0'
                aad
                cmp     ax,[bx]
                jb      rt20
                mov     dx,offset over_limit
rt16:           mov     ah,9
                int     21h
                jmp     short readtx

rt20:           stosw
                inc     bx
                inc     bx
                dec     cx
                jz      rt50
                lodsb
                cmp     al,':'
                jz      rt10
                cmp     al,0
                jz      rt50

rt40:           mov     dx,offset err_format
                jmp     short rt16

rt50:           call    count_limit
                jc      rt40
                ret

readtx:         stc
                ret
;------------------------------------------------------------------------------
count_limit:    cmp     minute,0
                jnz     cc20
                cmp     second,0
                jnz     cc20
cc10:           stc
                ret

cc20:           mov     ax,minute
                mov     bx,60
                mul     bx
                add     ax,second
                cmp     ax,limit_time
                jb      cc10
                mul     ratiob
                div     ratioa
                mov     delay_count,ax ;save user input
                clc
                ret
;------------------------------------------------------------------------------
cseg            ends
                end   begin                   ; end program


http://pan.baidu.com/s/1o6IFrHw